package com.angle3d.samples;

import android.content.Context;
import android.graphics.Bitmap;

import com.angle3d.Matrix4;
import com.angle3d.Mesh;
import com.angle3d.MeshUtil;
import com.angle3d.Node;
import com.angle3d.ShaderProgram;
import com.angle3d.ShaderSource;
import com.angle3d.ShaderSource.ShaderType;
import com.angle3d.Texture;

class SceneFactory {
	
	private final static String VertexShaderSource = 
		"precision highp float;" +
		"uniform mat4 ModelView;" +
		"uniform mat4 Projection;" +
		"attribute vec4 Position;" +
        "attribute vec3 Normal;" +
        "attribute vec2 TexCoord;" +
        "varying vec2 tcoord;" +
        "varying vec3 normal;" +
        "void main() {" +
        "tcoord = TexCoord;" +
        "normal = vec3(ModelView * vec4(Normal, 0.0));" +
        "gl_Position = Projection * ModelView * Position; }";
    
    private final static String FragmentShaderSource = 
        "precision mediump float;" +
        "uniform sampler2D Texture0;" +
        "uniform vec3 LightDir;" +
        "uniform vec3 DiffuseColor;" +
        "uniform vec3 AmbientColor;" +
        "uniform vec3 AmbientLight;" +
        "varying vec2 tcoord;" +
        "varying vec3 normal;" +
        "void main() {" +
        "vec3 ldir = normalize(LightDir);" +
        "vec3 n = normalize(normal);" +
        "float diffuseFactor = dot(n, ldir);" + 
        "vec4 texColor0 = texture2D(Texture0, tcoord);" +
        "gl_FragColor.a = texColor0.a; " +
        "gl_FragColor.rgb = texColor0.rgb * (AmbientColor * AmbientLight + diffuseFactor * DiffuseColor); }";
    
    private Mesh createTexturedCube(Context context) {
    	//create a mesh representing a cube
        Mesh mesh = MeshUtil.createBox(1, 1, 1);
		
        //create the vertex and fragment shaders to render our mesh
		ShaderSource vertex = new ShaderSource(VertexShaderSource, ShaderType.VERTEX);
        ShaderSource fragment = new ShaderSource(FragmentShaderSource, ShaderType.FRAGMENT);
        
        //specify the shader program for rendering the mesh
        mesh.setShaderProgram(new ShaderProgram(vertex, fragment) {
        	@Override
        	public void bind() {
        		super.bind();
        		
        		//specify value of specific uniform parameters for this shader
        		//note: we don't need to set the ModelView and Projection uniform parameters
        		//since those are default parameters automatically set by the Angle3D engine
        		this.setUniformValue("DiffuseColor", 0.0f, 1.0f, 0.0f);
        		this.setUniformValue("AmbientColor", 0.2f, 0.2f, 0.2f);
        		this.setUniformValue("AmbientLight", 0.8f, 0.8f, 0.8f);
        		this.setUniformValue("LightDir", 0.0f, 0.0f, 1.0f);
        	}
        });
        
        //create a texture to be applied on the mesh surface
        Texture texture = new Texture();
        Bitmap bm = SampleUtil.loadBitmap(R.drawable.brick, context);
        texture.setBitmap(bm);
        
        //set the texture in the mesh
        //note that the name "Texture0" must match the texture name in the Vertex shader source code
        mesh.setTexture(texture, "Texture0", 0);
    
        return mesh;
    }
    
	public Node createScene(Context context) {
		//create the scene root node
		Node scene = new Node();
        
		//create a cube mesh
		Mesh mesh = createTexturedCube(context);
		
		//create a node to host our mesh
		//we override the update() method to animate our node
        Node node = new Node() {
        	
        	private float time = 0;
        	
        	@Override
        	public void update(float dt) {
        		super.update(dt);
        		
        		time += dt;
        		
        		Matrix4 mat = this.getLocalMatrix();
        		mat.setIdentity();
        		mat.rotate(time, 0, 1, 0);
        	}
        };
        
        //attach the mesh to the node
        node.addSceneObject(mesh);
        
        //attach our mesh node as child of the scene root
        scene.addChild(node);
        
        //return our scene
        return scene;
	}
}
